from PySide6.QtWidgets import (
    QDialog, QVBoxLayout, QTableView, QLabel, QLineEdit,
    QPushButton, QHBoxLayout, QComboBox, QHeaderView,
    QFormLayout, QMessageBox, QProgressBar, QFileDialog,
    QSplitter, QFrame, QCheckBox, QSpinBox, QMenu,QStyle
)
from PySide6.QtCore import Qt, QThread, Signal, QTimer
from PySide6.QtGui import QStandardItemModel, QStandardItem, QColor
import pandas as pd
import numpy as np
import os
from typing import Optional, Dict, List, Tuple, Union


class DataProcessingThread(QThread):
    """数据处理线程，用于在后台执行数据处理任务"""
    progress_updated = Signal(int)
    processing_finished = Signal(pd.DataFrame)
    error_occurred = Signal(str)

    def __init__(self, df: pd.DataFrame, start_row: int, selected_columns: Dict[int, str]):
        super().__init__()
        self.df = df
        self.start_row = start_row
        self.selected_columns = selected_columns

    def run(self):
        try:
            total_steps = 4
            self.progress_updated.emit(10)  # 10%

            # 步骤1: 从起始行开始加载数据
            processed_df = self.df.iloc[self.start_row:].copy()
            self.progress_updated.emit(30)  # 30%

            # 步骤2: 重置索引
            processed_df = processed_df.reset_index(drop=True)
            self.progress_updated.emit(40)  # 40%

            # 步骤3: 创建列映射字典
            column_mapping = {}
            selected_column_names = []

            for col_idx, target_name in self.selected_columns.items():
                if col_idx < len(processed_df.columns):
                    original_col_name = processed_df.columns[col_idx]
                    column_mapping[original_col_name] = target_name
                    selected_column_names.append(target_name)

            self.progress_updated.emit(60)  # 60%

            # 步骤4: 重命名列并选择用户指定的列
            if column_mapping:
                processed_df.rename(columns=column_mapping, inplace=True)
                if selected_column_names:
                    processed_df = processed_df[selected_column_names]
            else:
                raise ValueError("没有有效的列映射，请检查字段选择")

            self.progress_updated.emit(90)  # 90%

            # 数据质量检查
            self._check_data_quality(processed_df)

            self.progress_updated.emit(100)  # 100%
            self.processing_finished.emit(processed_df)

        except Exception as e:
            self.error_occurred.emit(str(e))

    def _check_data_quality(self, df: pd.DataFrame) -> None:
        """检查数据质量并记录警告"""
        # 检查缺失值
        missing_values = df.isnull().sum().sum()
        if missing_values > 0:
            print(f"警告: 处理后的数据包含 {missing_values} 个缺失值")

        # 检查深度列是否有单调递增性
        depth_fields = ['斜深', '井深']
        depth_columns = [col for col in df.columns if col in depth_fields]
        for col in depth_columns:
            if pd.api.types.is_numeric_dtype(df[col]):
                if not df[col].is_monotonic_increasing:
                    print(f"警告: 深度列 '{col}' 不是单调递增的")


class DataImportDialog(QDialog):
    """数据导入对话框，用于设置字段映射和起始行"""

    # 预定义的标准字段列表
    STANDARD_FIELDS = [
        "不导入", "斜深", "井深"
    ]

    # 必须的字段列表
    REQUIRED_FIELDS = ["斜深", "井深"]

    def __init__(self, df: pd.DataFrame, parent=None, title: str = "数据导入 - 字段映射与起始行设置"):
        super().__init__(parent)
        self.setWindowTitle(title)
        self.setMinimumSize(1000, 700)
        self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint)

        # 保存原始数据并创建副本用于处理
        self.original_df = df
        self.df = df.copy()  # 复制DataFrame防止修改原始数据
        self.selected_columns = {}  # 存储列映射关系：{原始列索引: 目标列名}
        self.start_row = 0  # 默认起始行为0
        self.selected_row = -1  # 当前选中的行索引
        self.is_processing = False  # 数据处理状态
        self.data_preview_limit = 100  # 默认预览行数
        self.thread = None  # 初始化线程对象

        # 数据质量指标
        self.data_quality_metrics = {
            'rows': len(self.df),
            'columns': len(self.df.columns),
            'missing_values': self.df.isnull().sum().sum(),
            'numeric_columns': len(self.df.select_dtypes(include=[np.number]).columns)
        }

        self.init_ui()

    def init_ui(self):
        """初始化用户界面"""
        main_layout = QVBoxLayout(self)

        # 顶部信息面板
        info_panel = QFormLayout()

        self.filename_label = QLabel(self.original_df.shape[
                                         1] > 0 and f"{self.original_df.shape[0]} 行 {self.original_df.shape[1]} 列" or "空数据")
        self.encoding_label = QLabel("UTF-8")
        self.missing_values_label = QLabel(f"{self.data_quality_metrics['missing_values']} 个缺失值")
        self.numeric_columns_label = QLabel(f"{self.data_quality_metrics['numeric_columns']} 个数字列")

        info_panel.addRow("数据维度:", self.filename_label)
        info_panel.addRow("编码格式:", self.encoding_label)
        info_panel.addRow("缺失值:", self.missing_values_label)
        info_panel.addRow("数字列:", self.numeric_columns_label)

        main_layout.addLayout(info_panel)

        # 创建分割器，允许用户调整预览和设置区域的大小
        splitter = QSplitter(Qt.Vertical)

        # 数据预览区域
        preview_frame = QFrame()
        preview_layout = QVBoxLayout(preview_frame)

        # 预览控制栏
        control_layout = QHBoxLayout()

        self.preview_limit_label = QLabel("预览行数:")
        self.preview_limit_spin = QSpinBox()
        self.preview_limit_spin.setRange(10, 1000)
        self.preview_limit_spin.setValue(self.data_preview_limit)
        self.preview_limit_spin.valueChanged.connect(self._update_preview)

        self.refresh_btn = QPushButton("刷新预览")
        self.refresh_btn.clicked.connect(self._update_preview)

        control_layout.addWidget(self.preview_limit_label)
        control_layout.addWidget(self.preview_limit_spin)
        control_layout.addWidget(self.refresh_btn)
        control_layout.addStretch()

        preview_layout.addLayout(control_layout)

        # 表格预览
        self.table_model = QStandardItemModel()
        self.table_view = QTableView()
        self.table_view.setModel(self.table_model)
        self.table_view.setSelectionBehavior(QTableView.SelectRows)  # 设置选择行为为选择整行
        self.table_view.setEditTriggers(QTableView.NoEditTriggers)  # 禁止编辑
        self.table_view.verticalHeader().setDefaultSectionSize(24)  # 设置行高
        self.table_view.horizontalHeader().setStretchLastSection(True)  # 最后一列自动拉伸
        self.table_view.setAlternatingRowColors(True)  # 交替行颜色

        # 双击行事件 - 选择起始行
        self.table_view.doubleClicked.connect(self.on_row_double_clicked)



        # 右键菜单支持
        self.table_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table_view.customContextMenuRequested.connect(self.show_context_menu)

        preview_layout.addWidget(QLabel("数据预览（双击选择起始行）:"))
        preview_layout.addWidget(self.table_view)

        # 操作提示
        self.hint_label = QLabel("请双击左侧行号选择起始行")
        self.hint_label.setStyleSheet("color: gray;")
        preview_layout.addWidget(self.hint_label)

        splitter.addWidget(preview_frame)

        # 映射设置区域
        mapping_frame = QFrame()
        mapping_layout = QVBoxLayout(mapping_frame)

        # 映射摘要信息
        self.mapping_summary_label = QLabel("未选择起始行")
        mapping_layout.addWidget(self.mapping_summary_label)

        # 映射配置表格
        self.mapping_model = QStandardItemModel()
        self.mapping_model.setHorizontalHeaderLabels(["原始列名", "映射类型", "目标列名"])
        self.mapping_view = QTableView()
        self.mapping_view.setModel(self.mapping_model)
        self.mapping_view.setSelectionBehavior(QTableView.SelectRows)
        self.mapping_view.setEditTriggers(QTableView.NoEditTriggers)
        self.mapping_view.verticalHeader().setVisible(False)
        self.mapping_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.mapping_view.setAlternatingRowColors(True)

        self.mapping_view.clicked.connect(self.on_mapping_cell_clicked)

        mapping_layout.addWidget(QLabel("字段映射配置:"))
        mapping_layout.addWidget(self.mapping_view)

        # 自动映射按钮
        auto_map_btn = QPushButton("自动映射")
        auto_map_btn.setToolTip("尝试根据列名自动匹配标准字段")
        auto_map_btn.clicked.connect(self.auto_map_columns)
        mapping_layout.addWidget(auto_map_btn)

        splitter.addWidget(mapping_frame)

        # 设置分割器初始大小
        splitter.setSizes([400, 300])

        main_layout.addWidget(splitter)

        # 底部进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.hide()
        main_layout.addWidget(self.progress_bar)

        # 按钮区域
        btn_layout = QHBoxLayout()
        confirm_btn = QPushButton("确认")
        cancel_btn = QPushButton("取消")
        reset_btn = QPushButton("重置")

        confirm_btn.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogOkButton))
        cancel_btn.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogOkButton))
        reset_btn.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogOkButton))

        confirm_btn.clicked.connect(self.on_confirm)
        cancel_btn.clicked.connect(self.reject)
        reset_btn.clicked.connect(self.reset_selection)

        btn_layout.addStretch()
        btn_layout.addWidget(reset_btn)
        btn_layout.addWidget(confirm_btn)
        btn_layout.addWidget(cancel_btn)
        main_layout.addLayout(btn_layout)

        # 加载数据到表格预览
        self._load_data_to_model()

    def reset_selection(self):
        """重置所有选择"""
        self.selected_columns.clear()
        self.start_row = 0
        self.selected_row = -1
        self._load_data_to_model()
        self.hint_label.setText("请双击左侧行号选择起始行")
        self.mapping_summary_label.setText("未选择起始行")
        self.mapping_model.removeRows(0, self.mapping_model.rowCount())

        # 重置表格样式
        for col_idx in range(self.table_model.columnCount()):
            for row_idx in range(self.table_model.rowCount()):
                index = self.table_model.index(row_idx, col_idx)
                self.table_model.setData(index, QColor(255, 255, 255), Qt.BackgroundRole)

    def _load_data_to_model(self):
        """加载数据到表格模型"""
        self.table_model.clear()

        # 使用实际列名作为表头
        self.table_model.setHorizontalHeaderLabels(self.df.columns.tolist())

        # 加载数据
        max_preview_rows = min(len(self.df), self.data_preview_limit)
        for row_idx, row in enumerate(self.df.head(max_preview_rows).itertuples(index=False)):
            items = [QStandardItem(str(value)) for value in row]
            for item in items:
                item.setEditable(False)
            self.table_model.appendRow(items)

        # 设置表格样式
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)

        # 显示预览提示
        if len(self.df) > max_preview_rows:
            self.hint_label.setText(f"已加载前 {max_preview_rows} 行数据进行字段映射（总 {len(self.df)} 行）")
        else:
            self.hint_label.setText("请双击左侧行号选择起始行")

    def _update_preview(self):
        """更新数据预览"""
        self.data_preview_limit = self.preview_limit_spin.value()
        self._load_data_to_model()

        # 如果已经选择了起始行，重新高亮显示
        if self.selected_row >= 0:
            self.highlight_selected_row()


    def on_mapping_cell_clicked(self, index):
        """处理映射表格单元格点击事件"""
        row = index.row()
        col = index.column()

        if col == 2:  # 只处理目标列名列
            original_col_name = self.mapping_model.item(row, 0).text()
            col_idx = list(self.df.columns).index(original_col_name)

            # 弹出输入对话框
            from PySide6.QtWidgets import QInputDialog, QCompleter

            dialog = QInputDialog(self)
            dialog.setWindowTitle("映射列")
            dialog.setLabelText(f"将列 '{original_col_name}' 映射为:")

            # 构建选项列表，包含标准字段、必填项和当前列的表头名
            options = self.STANDARD_FIELDS.copy()
            if original_col_name not in options:
                options.append(original_col_name)

            dialog.setComboBoxItems(options)
            dialog.setComboBoxEditable(True)

            # 添加自动完成功能
            completer = QCompleter(self.STANDARD_FIELDS)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            dialog.findChild(QLineEdit).setCompleter(completer)

            if dialog.exec_():
                target_name = dialog.textValue()
                if target_name and target_name != "不导入":
                    self.selected_columns[col_idx] = target_name
                else:
                    if col_idx in self.selected_columns:
                        del self.selected_columns[col_idx]
                self.update_mapping_table()

    def on_row_double_clicked(self, index):
        """处理行双击事件"""
        row = index.row()
        self.start_row = row
        self.selected_row = row
        self.hint_label.setText(f"已选择第 {row} 行作为起始行，请设置字段映射")
        self.mapping_summary_label.setText(f"起始行: {row}，请配置字段映射")

        # 高亮显示选中的行
        self.highlight_selected_row()

        # 更新映射表格
        self.update_mapping_table()

    def highlight_selected_row(self):
        """高亮显示选中的起始行"""
        # 重置所有行的样式
        for col_idx in range(self.table_model.columnCount()):
            for row_idx in range(self.table_model.rowCount()):
                index = self.table_model.index(row_idx, col_idx)
                self.table_model.setData(index, QColor(255, 255, 255), Qt.BackgroundRole)

        # 高亮显示选中的行
        if 0 <= self.selected_row < self.table_model.rowCount():
            for col_idx in range(self.table_model.columnCount()):
                index = self.table_model.index(self.selected_row, col_idx)
                self.table_model.setData(index, QColor(220, 230, 255), Qt.BackgroundRole)

    def update_mapping_table(self):
        """更新映射配置表格"""
        self.mapping_model.removeRows(0, self.mapping_model.rowCount())

        # 添加映射配置行
        for col_idx in range(min(self.table_model.columnCount(), len(self.df.columns))):
            original_col_name = self.df.columns[col_idx]

            # 创建原始列名项
            original_item = QStandardItem(original_col_name)

            # 创建映射类型项
            map_type_item = QStandardItem()

            # 创建目标列名项
            target_item = QStandardItem()

            # 如果该列已被映射
            if col_idx in self.selected_columns:
                target_name = self.selected_columns[col_idx]
                map_type_item.setText("映射")

                # 为必须字段添加特殊样式
                if target_name in self.REQUIRED_FIELDS:
                    map_type_item.setData(QColor(100, 149, 237), Qt.BackgroundRole)
                    target_item.setData(QColor(100, 149, 237), Qt.ForegroundRole)
                else:
                    map_type_item.setData(QColor(144, 238, 144), Qt.BackgroundRole)

                target_item.setText(target_name)
            else:
                map_type_item.setText("忽略")
                map_type_item.setData(QColor(255, 182, 193), Qt.BackgroundRole)
                target_item.setText("")

            # 添加到模型
            self.mapping_model.appendRow([original_item, map_type_item, target_item])

    def show_context_menu(self, position):
        """显示右键菜单"""
        index = self.table_view.indexAt(position)
        if index.isValid():
            col_idx = index.column()

            menu = QMenu()

            # 添加映射选项
            map_action = menu.addAction("映射列")
            map_action.triggered.connect(lambda: self.map_column(col_idx))

            # 如果该列已被映射，添加取消映射选项
            if col_idx in self.selected_columns:
                unmap_action = menu.addAction("取消映射")
                unmap_action.triggered.connect(lambda: self.unmap_column(col_idx))

            menu.exec_(self.table_view.viewport().mapToGlobal(position))

    def map_column(self, col_idx):
        """映射指定列"""
        from PySide6.QtWidgets import QInputDialog, QCompleter

        # 创建输入对话框
        dialog = QInputDialog(self)
        dialog.setWindowTitle("映射列")
        dialog.setLabelText(f"将列 '{self.df.columns[col_idx]}' 映射为:")
        dialog.setComboBoxItems(self.STANDARD_FIELDS)
        dialog.setComboBoxEditable(True)

        # 添加自动完成功能
        completer = QCompleter(self.STANDARD_FIELDS)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        dialog.findChild(QLineEdit).setCompleter(completer)

        if dialog.exec_():
            target_name = dialog.textValue()
            if target_name and target_name != "不导入":
                self.selected_columns[col_idx] = target_name
                self.update_mapping_table()

    def unmap_column(self, col_idx):
        """取消映射指定列"""
        if col_idx in self.selected_columns:
            del self.selected_columns[col_idx]
            self.update_mapping_table()

    def auto_map_columns(self):
        """尝试自动映射列"""
        if self.selected_row < 0:
            QMessageBox.warning(self, "警告", "请先选择起始行")
            return

        # 清空现有映射
        self.selected_columns.clear()

        # 尝试根据列名自动映射
        for col_idx, original_col_name in enumerate(self.df.columns):
            original_lower = original_col_name.lower()

            # 查找最佳匹配的标准字段
            best_match = None
            highest_similarity = 0

            for standard_field in self.STANDARD_FIELDS:
                if standard_field == "不导入":
                    continue

                standard_lower = standard_field.lower()

                # 简单的相似度计算
                if standard_lower in original_lower:
                    similarity = len(standard_lower) / len(original_lower)
                    if similarity > highest_similarity:
                        highest_similarity = similarity
                        best_match = standard_field

            # 如果相似度足够高，进行映射
            if best_match and highest_similarity >= 0.3:
                self.selected_columns[col_idx] = best_match

        # 更新映射表格
        self.update_mapping_table()

        # 显示提示
        mapped_count = len(self.selected_columns)
        total_count = len(self.df.columns)
        self.hint_label.setText(f"已自动映射 {mapped_count}/{total_count} 列")

    def on_confirm(self):
        """处理确认按钮点击"""
        # 验证字段选择
        if not self.selected_columns:
            QMessageBox.warning(self, "警告", "请至少选择一个有效字段")
            return

        # 验证必要字段
        depth_fields = ['斜深', '井深']
        if not any(name in depth_fields for name in self.selected_columns.values()):
            result = QMessageBox.question(
                self, "提示",
                "您尚未选择任何深度字段（斜深/井深），这可能会影响后续分析。是否继续？",
                QMessageBox.Yes | QMessageBox.No
            )
            if result == QMessageBox.No:
                return

        # 验证起始行是否超出数据范围
        if self.start_row >= len(self.df):
            QMessageBox.warning(self, "警告", f"起始行 {self.start_row} 超出数据范围（总行数: {len(self.df)}）")
            return

        # 在后台线程中处理数据
        if self.is_processing:
            return
        self.is_processing = True
        self.progress_bar.show()
        self.progress_bar.setValue(0)

        self.thread = DataProcessingThread(self.df, self.start_row, self.selected_columns)
        self.thread.progress_updated.connect(self.update_progress)
        self.thread.processing_finished.connect(self.processing_finished)
        self.thread.error_occurred.connect(self.processing_error)
        self.thread.start()

    def update_progress(self, progress):
        """更新进度条"""
        self.progress_bar.setValue(progress)

    def processing_finished(self, processed_df):
        """数据处理完成"""
        self.processed_data=processed_df
        self.is_processing = False
        self.progress_bar.hide()
        self.accept()
        # 这里可以添加将处理后的数据传递给其他部分的逻辑
        print("数据处理完成，处理后的数据如下：")
        print(processed_df)

    def processing_error(self, error):
        """数据处理出错"""
        self.is_processing = False
        self.progress_bar.hide()
        QMessageBox.critical(self, "错误", f"数据处理出错: {error}")